﻿using GalaSoft.MvvmLight;
using AutoCorrelatorGUI.Model;
using GalaSoft.MvvmLight.CommandWpf;
using System.Windows;
using System.Collections.Generic;
using AutoCorrelatorGUI.Properties;
using System.Collections.ObjectModel;
using OxyPlot;
using System.Windows.Data;
using System;
using System.ComponentModel;
using AutoCorrelatorGUI.Utility;
using System.Windows.Controls;
using System.Windows.Media;
using GalaSoft.MvvmLight.Messaging;
using AutoCorrelatorGUI.View;
using System.Windows.Controls.Primitives;
using AutoCorrelatorGUI.ViewModel.Messages;
using Microsoft.Win32;
using System.Linq;
using Common.Utility;
using Common.ViewModel;

namespace AutoCorrelatorGUI.ViewModel
{
   /// <summary>
   /// This class contains properties that the main View can data bind to.
   /// <para>
   /// See http://www.galasoft.ch/mvvm
   /// </para>
   /// </summary>
   public class MainViewModel : ViewModelBase
   {
      private StatsColumnManager _StatsManager = null;
      private IDataService _DataService = null;

      /// <summary>
      /// Initializes a new instance of the MainViewModel class.
      /// </summary>
      public MainViewModel(IDataService dataService)
      {
         Settings.Default.Reload();
         _DataService = dataService;

         //Set all the defaults from the file
         _DataService.SetCalcDerivative(Settings.Default.CalcFirstDerivative);
         _DataService.SetNormalization(Settings.Default.NormalizationMethod);
         _DataService.SetCompareWell(Settings.Default.ComparisonWellStr);
         _DataService.SetIntervalTime(Settings.Default.IntervalTimeMS);

         //Listen to added components that need to get any existing data
         Messenger.Default.Register<RequestDataMessage>(this, ComponentRequestData);

         _DataService.DataUpdated += _DataService_DataUpdated;

         Style headerColorStyle = new Style(typeof(TextBlock));
         headerColorStyle.Setters.Add(new Setter(TextBlock.BackgroundProperty, new Binding("Color") { Converter = new ColorToBrushConverter() }));

         StatsPanelColumnCollection = new ObservableCollection<DataGridColumn>();
         StatsPanelColumnCollection.Add(new DataGridTextColumn() { Header = "ID", Binding = new Binding("Title"), ElementStyle = headerColorStyle, IsReadOnly = true });

         if (Settings.Default.StatsColumns == null)
            Settings.Default.StatsColumns = new StatsColumnManager();

         _StatsManager = Settings.Default.StatsColumns;
         _StatsManager.Columns = StatsPanelColumnCollection;

         //Make sure to send the default value to the data service
         _DataService.SetInputFile(Settings.Default.InputFile, Settings.Default.PerformAutoCorrelation);

         _DataService.StatusMessage += _DataService_StatusMessage;
      }

      private MultiSelectBindingList<WellVM> _WellData = null;

      public MultiSelectBindingList<WellVM> WellData
      {
         get { return _WellData; }
         set
         {
            //Need to move the event handlers
            if (_WellData != null)
            {
               _WellData.ListChanged -= _WellData_ListChanged;
               _WellData.SelectedItems.ListChanged -= _WellData_SelectedItems_ListChanged;
            }

            _WellData = value;

            if (_WellData != null)
            {
               _WellData.ListChanged += _WellData_ListChanged;
               _WellData.SelectedItems.ListChanged += _WellData_SelectedItems_ListChanged;
               _WellDataView = new ListCollectionView(_WellData);
               _WellDataView.CurrentChanging += _WellDataView_CurrentChanging;
            }
         }
      }

      private ListCollectionView _WellDataView = null;

      public ListCollectionView WellDataView
      {
         get
         {
            return _WellDataView;
         }
      }

      /// <summary>
      /// The <see cref="StatsPanelVisible" /> property's name.
      /// </summary>
      public const string StatsPanelVisiblePropertyName = "StatsPanelVisible";

      /// <summary>
      /// Sets and gets the StatsPanelVisible property.
      /// Changes to that property's value raise the PropertyChanged event. 
      /// </summary>
      public bool StatsPanelVisible
      {
         get
         {
            return Settings.Default.StatsPanelVisible;
         }

         set
         {
            if (Settings.Default.StatsPanelVisible == value)
            {
               return;
            }

            Settings.Default.StatsPanelVisible = value;
            RaisePropertyChanged(StatsPanelVisiblePropertyName);
         }
      }

      public ObservableCollection<DataGridColumn> StatsPanelColumnCollection
      {
         get;
         private set;
      }

      private void _DataService_StatusMessage(string obj)
      {
         MessageBox.Show(obj);
      }

      private void _DataService_DataUpdated(DataUpdateTypes obj)
      {
         switch (obj)
         {
         case DataUpdateTypes.Full:
            WellsFullUpdate();
            break;
         default:
            WellDataView.Refresh();
            Messenger.Default.Send(new DataUpdateMessage(obj));
            break;
         }
      }

      void _WellDataView_CurrentChanging(object sender, CurrentChangingEventArgs e)
      {
         if (e.IsCancelable)
            e.Cancel = true;
      }

      void _WellData_ListChanged(object sender, ListChangedEventArgs e)
      {
         if (e.ListChangedType == ListChangedType.ItemAdded ||
            e.ListChangedType == ListChangedType.ItemDeleted ||
            e.ListChangedType == ListChangedType.ItemMoved ||
            e.ListChangedType == ListChangedType.Reset)
         {
            //UpdatePlot();
         }
      }

      void _WellData_SelectedItems_ListChanged(object sender, ListChangedEventArgs e)
      {
         if (e.ListChangedType != ListChangedType.Reset)
            return;

         BindingList<WellVM> selected = (sender as BindingList<WellVM>);

         int visibleSelected = 0;

         foreach (var well in selected)
         {
            if (well.Visible)
            {
               visibleSelected++;
            }
         }

         bool isMulti = visibleSelected > 1;

         foreach (var well in WellData)
         {
            if (well.Visible && selected.Contains(well))
            {
               if (isMulti)
               {
                  well.Focus = FocusLevels.Normal;
               }
               else
               {
                  well.Focus = FocusLevels.High;
               }
            }
            else
            {
               if (isMulti)
               {
                  well.Focus = FocusLevels.Low;
               }
               else
               {
                  well.Focus = FocusLevels.Normal;
               }
            }
         }
      }

      private void WellsFullUpdate()
      {
         //Clear out the old stuff and make way for new items
         MultiSelectBindingList<WellVM> newList = new MultiSelectBindingList<WellVM>();

         _DataService.GetAllWells((IList<Well> w) =>
         {

            for (int i = 0; i < w.Count; i++)
            {
               OxyColor indexColor = DefaultPalettes.Color[i % DefaultPalettes.Color.Count];

               newList.Add(new WellVM(w[i]) { Color = Color.FromArgb(indexColor.A, indexColor.R, indexColor.G, indexColor.B) });
            }

         });

         WellData = newList;

         int minX = Int32.MaxValue;
         int maxX = Int32.MinValue;

         foreach (WellVM well in WellData)
         {
            minX = Math.Min(minX, well.Output.DataStore.Keys.Min());
            maxX = Math.Max(maxX, well.Output.DataStore.Keys.Max());
         }

         _StatsManager.SetIOColumnCount((maxX - minX) + 1, minX, maxX);
         WellDataView.Refresh();

         Messenger.Default.Send(new FullRefreshMessage(WellDataView));
      }

      private void ComponentRequestData(RequestDataMessage request)
      {
         if (WellDataView == null)
            return;

         request.RequestData(new FullRefreshMessage(WellDataView));
      }

      #region Commands

      private RelayCommand _OpenFileDialogCommand = null;

      /// <summary>
      /// Gets the OpenFileDialog.
      /// </summary>
      public RelayCommand OpenFileDialogCommand
      {
         get
         {
            return _OpenFileDialogCommand ?? (_OpenFileDialogCommand = new RelayCommand(
               () =>
               {
                  Messenger.Default.Send(new MenuCommandMessage(MenuCommandTypes.Open));
               }));
         }
      }

      private RelayCommand _LoadInputFileCommand;

      /// <summary>
      /// Gets the LoadInputFile.
      /// </summary>
      public RelayCommand LoadInputFileCommand
      {
         get
         {
            return _LoadInputFileCommand
                ?? (_LoadInputFileCommand = new RelayCommand(
                   () =>
                   {
                      Messenger.Default.Send(new MenuCommandMessage(MenuCommandTypes.ProcessInput));
                   }));
         }
      }

      private RelayCommand _SaveOutputDataCommand;

      /// <summary>
      /// Gets the SaveOutputData.
      /// </summary>
      public RelayCommand SaveOutputDataCommand
      {
         get
         {
            return _SaveOutputDataCommand
                ?? (_SaveOutputDataCommand = new RelayCommand(
                   () =>
                   {
                      SaveFileDialog sfd = new SaveFileDialog();
                      sfd.AddExtension = true;
                      sfd.DefaultExt = ".csv";
                      sfd.Filter = "Comma Separated Values (*.csv)|*.csv|All Files (*.*)|*.*";
                      if (!sfd.ShowDialog().GetValueOrDefault(false))
                         return;

                      _DataService.SaveOutputData(sfd.FileName);
                   }));
         }
      }

      private RelayCommand _ExitCommand;

      /// <summary>
      /// Gets the MyCommand.
      /// </summary>
      public RelayCommand ExitCommand
      {
         get
         {
            return _ExitCommand
                ?? (_ExitCommand = new RelayCommand(
                () =>
                {
                   Application.Current.Shutdown();
                }));
         }
      }

      private RelayCommand<CancelEventArgs> _ClosingCommand = null;

      public RelayCommand<CancelEventArgs> ClosingCommand
      {
         get
         {
            return _ClosingCommand
                ?? (_ClosingCommand = new RelayCommand<CancelEventArgs>(
                (args) =>
                {
                   ExitCommand.Execute(null);
                }));
         }
      }

      private RelayCommand _ClearStatsPanelCommand;

      /// <summary>
      /// Gets the ClearStatsPanelCommand.
      /// </summary>
      public RelayCommand ClearStatsPanelCommand
      {
         get
         {
            return _ClearStatsPanelCommand
                ?? (_ClearStatsPanelCommand = new RelayCommand(
                () =>
                {
                   _StatsManager.ClearChecks();
                }));
         }
      }

      private RelayCommand _ShowStatsColumnSelectCommand;

      /// <summary>
      /// Gets the ShowStatsColumnSelectCommand.
      /// </summary>
      public RelayCommand ShowStatsColumnSelectCommand
      {
         get
         {
            return _ShowStatsColumnSelectCommand
                ?? (_ShowStatsColumnSelectCommand = new RelayCommand(
                () =>
                {
                   var columnView = new StatsColumnSelectView();
                   (columnView.DataContext as StatsColumnSelectViewModel).StatsColumns = _StatsManager.Items;
                   columnView.ShowDialog();
                }));
         }
      }

      private RelayCommand _OpenNewDisplayWindowCommand;

      /// <summary>
      /// Gets the ShowStatsColumnSelectCommand.
      /// </summary>
      public RelayCommand OpenNewDisplayWindowCommand
      {
         get
         {
            return _OpenNewDisplayWindowCommand
                ?? (_OpenNewDisplayWindowCommand = new RelayCommand(
                () =>
                {
                   var dataWindow = new DataDisplayWindow();
                   dataWindow.Show();
                }));
         }
      }

      #endregion
   }
}